feat: migrate v1 state into orchestrator v2#4400
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
| const suffix = | ||
| section.length <= remaining ? section : section.slice(section.length - remaining); | ||
| selected.unshift(suffix); |
There was a problem hiding this comment.
🟡 Medium orchestration-v2/ContextHandoffService.ts:182
makeLegacyImportSummary truncates from the left when a section exceeds the remaining character budget, taking a raw suffix via section.slice(section.length - remaining). When this cut lands inside the first retained section, the User: or Assistant: label is dropped and the text can start mid-word, so the imported context begins with unattributed, fragmentary text. Consider preserving the role prefix and truncating only the message body, or omitting the partial section entirely.
| const suffix = | |
| section.length <= remaining ? section : section.slice(section.length - remaining); | |
| selected.unshift(suffix); | |
| const suffix = | |
| section.length <= remaining | |
| ? section | |
| : section.slice(section.length - remaining); | |
| selected.unshift(suffix); |
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/server/src/orchestration-v2/ContextHandoffService.ts around lines 182-184:
`makeLegacyImportSummary` truncates from the left when a section exceeds the remaining character budget, taking a raw suffix via `section.slice(section.length - remaining)`. When this cut lands inside the first retained section, the `User:` or `Assistant:` label is dropped and the text can start mid-word, so the imported context begins with unattributed, fragmentary text. Consider preserving the role prefix and truncating only the message body, or omitting the partial section entirely.
| const getThreadSnapshot: ThreadManagementServiceShape["getThreadSnapshot"] = (threadId) => | ||
| ensureLegacyTranscript(threadId).pipe(Effect.andThen(orchestrator.getThreadSnapshot(threadId))); | ||
|
|
||
| const dispatch: ThreadManagementServiceShape["dispatch"] = (command) => { |
There was a problem hiding this comment.
🟠 High orchestration-v2/ThreadManagementService.ts:261
The dispatch wrapper only calls ensureLegacyTranscript for message.dispatch, thread.fork, and thread.merge_back. All other commands targeting an existing migrated thread — such as thread.metadata.update, thread.archive, or thread.delete — bypass hydration and dispatch directly. When a later projection read triggers the importer, its transcript marker emits a thread.metadata-updated event from the stale v1 row, overwriting the newer title/archive/deletion metadata. Hydrate every command that operates on an existing thread before dispatching, not just those three types.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/server/src/orchestration-v2/ThreadManagementService.ts around line 261:
The `dispatch` wrapper only calls `ensureLegacyTranscript` for `message.dispatch`, `thread.fork`, and `thread.merge_back`. All other commands targeting an existing migrated thread — such as `thread.metadata.update`, `thread.archive`, or `thread.delete` — bypass hydration and dispatch directly. When a later projection read triggers the importer, its transcript marker emits a `thread.metadata-updated` event from the stale v1 row, overwriting the newer title/archive/deletion metadata. Hydrate every command that operates on an existing thread before dispatching, not just those three types.
| const ensureLegacyTranscript = (threadId: ThreadId) => | ||
| legacyImporter.ensureTranscript(threadId).pipe( | ||
| Effect.tapError((cause) => | ||
| Effect.logWarning("Unable to hydrate migrated v1 thread transcript", { | ||
| threadId, | ||
| cause, | ||
| }), | ||
| ), | ||
| Effect.ignore, | ||
| ); |
There was a problem hiding this comment.
🟡 Medium orchestration-v2/ThreadManagementService.ts:242
ensureLegacyTranscript swallows all hydration failures with Effect.ignore, so every call site (dispatch, getThreadProjection, getThreadSnapshot) proceeds as if the legacy transcript was loaded even when it wasn't. For message.dispatch this means the provider turn is built from only the shell preview instead of the full legacy conversation — context omitted from that turn cannot be restored by a later retry. Consider letting hydration failures propagate (or retrying) so dispatch does not silently continue with an incomplete transcript.
- const ensureLegacyTranscript = (threadId: ThreadId) =>
- legacyImporter.ensureTranscript(threadId).pipe(
- Effect.tapError((cause) =>
- Effect.logWarning("Unable to hydrate migrated v1 thread transcript", {
- threadId,
- cause,
- }),
- ),
- Effect.ignore,
- );
+ const ensureLegacyTranscript = (threadId: ThreadId) =>
+ legacyImporter.ensureTranscript(threadId).pipe(
+ Effect.tapError((cause) =>
+ Effect.logWarning("Unable to hydrate migrated v1 thread transcript", {
+ threadId,
+ cause,
+ }),
+ ),
+ );🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/server/src/orchestration-v2/ThreadManagementService.ts around lines 242-251:
`ensureLegacyTranscript` swallows all hydration failures with `Effect.ignore`, so every call site (`dispatch`, `getThreadProjection`, `getThreadSnapshot`) proceeds as if the legacy transcript was loaded even when it wasn't. For `message.dispatch` this means the provider turn is built from only the shell preview instead of the full legacy conversation — context omitted from that turn cannot be restored by a later retry. Consider letting hydration failures propagate (or retrying) so dispatch does not silently continue with an incomplete transcript.
0fff2d0 to
1d15173
Compare
| lineage: projection.thread.lineage, | ||
| forkedFrom: projection.thread.forkedFrom, | ||
| activeProviderThreadId: projection.thread.activeProviderThreadId, | ||
| ...(projection.thread.historyOrigin === undefined |
There was a problem hiding this comment.
🟡 Medium orchestration-v2/ProjectionStore.ts:769
Production shell snapshots silently drop historyOrigin from imported threads, while in-memory/test snapshots include it. threadShellFromProjection (used by the in-memory store) now propagates historyOrigin as an optional field, but the production shellFromState constructor still omits input.state.thread.historyOrigin, so the field is lost for all production shell snapshots. Add the same optional-field propagation to shellFromState.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/server/src/orchestration-v2/ProjectionStore.ts around line 769:
Production shell snapshots silently drop `historyOrigin` from imported threads, while in-memory/test snapshots include it. `threadShellFromProjection` (used by the in-memory store) now propagates `historyOrigin` as an optional field, but the production `shellFromState` constructor still omits `input.state.thread.historyOrigin`, so the field is lost for all production shell snapshots. Add the same optional-field propagation to `shellFromState`.
| ); | ||
| } | ||
|
|
||
| export const ChatHeader = memo(function ChatHeader({ |
There was a problem hiding this comment.
🟡 Medium chat/ChatHeader.tsx:11
Scripts declared in a project's checked-in t3.json are no longer shown anywhere in the UI. The old ChatHeader called useT3ProjectFileScripts and passed the result as fileScripts to ProjectScriptsControl; after this PR removes that call site, fileScripts is never populated, so ProjectScriptsControl only sees the default empty array and the file-based scripts disappear from the picker. Wire useT3ProjectFileScripts back into wherever ProjectScriptsControl is now rendered (e.g., ThreadDetailsPanel) and pass its result as fileScripts.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/components/chat/ChatHeader.tsx around line 11:
Scripts declared in a project's checked-in `t3.json` are no longer shown anywhere in the UI. The old `ChatHeader` called `useT3ProjectFileScripts` and passed the result as `fileScripts` to `ProjectScriptsControl`; after this PR removes that call site, `fileScripts` is never populated, so `ProjectScriptsControl` only sees the default empty array and the file-based scripts disappear from the picker. Wire `useT3ProjectFileScripts` back into wherever `ProjectScriptsControl` is now rendered (e.g., `ThreadDetailsPanel`) and pass its result as `fileScripts`.
a5b5085 to
952df09
Compare
4f338ff to
4e8f03a
Compare
6b1c011 to
cd04ad1
Compare
4e8f03a to
c827eba
Compare
cd04ad1 to
1e58e65
Compare
c827eba to
1842ade
Compare
1e58e65 to
a286c60
Compare
1842ade to
f9f39db
Compare
25e9e1b to
f845ccf
Compare
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
f845ccf to
8008280
Compare
Summary
userdatadirectoryMigration behavior
projection_thread_messagesafter command readiness and on first open/dispatchVerification
Stacked on #2829. The released migration-order repair now lives in the parent PR.